package cn.iocoder.yudao.module.scrm.controller.admin.clue;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.enums.ExcelColumn;
import cn.iocoder.yudao.framework.excel.core.strategy.DictTenantContext;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.scrm.annotations.EncryptPhoneNumbers;
import cn.iocoder.yudao.module.scrm.controller.admin.clue.vo.*;
import cn.iocoder.yudao.module.scrm.controller.admin.customer.vo.CustomerRespVO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.clue.ClueDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.customer.CustomerDO;
import cn.iocoder.yudao.module.scrm.service.clue.ClueService;
import cn.iocoder.yudao.module.scrm.util.ImportTemplateRandomByTenant;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.compress.archivers.dump.InvalidFormatException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.scrm.enums.DictTypeConstants.*;
import static cn.iocoder.yudao.module.scrm.enums.ErrorCodeConstants.*;
import static java.util.Collections.singletonList;

/**
 * @author Administrator
 */
@Tag(name = "管理后台 - SCRM 线索")
@RestController
@RequestMapping("/scrm/clue")
@Validated
public class ClueController {

    @Resource
    private ClueService clueService;

    @Resource
    private DictDataApi dictDataApi;

    @Resource
    private PermissionApi permissionApi;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private DeptApi deptApi;


    @PostMapping("/create")
    @Operation(summary = "创建线索")
    @PreAuthorize("@ss.hasPermission('scrm:clue:create')")
    public CommonResult<Integer> createClue(@Valid @RequestBody ClueSaveReqVO createReqVO) {
        return success(clueService.createClue(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新线索")
    @PreAuthorize("@ss.hasPermission('scrm:clue:update')")
    public CommonResult<Boolean> updateClue(@Valid @RequestBody ClueSaveReqVO updateReqVO) {
        clueService.updateClue(updateReqVO);
        return success(true);
    }


    @DeleteMapping("/delete")
    @Operation(summary = "删除线索")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('scrm:clue:delete')")
    public CommonResult<Boolean> deleteClue(@RequestParam("id") Integer id) {
        clueService.deleteClue(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得线索")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('scrm:clue:query')")
    @EncryptPhoneNumbers
    public CommonResult<ClueRespVO> getClue(@RequestParam("id") Integer id) {
        ClueDO clue = clueService.getClue(id);
        return success(BeanUtils.toBean(clue, ClueRespVO.class));
    }

    @GetMapping("/getDetail")
    @Operation(summary = "获得线索详情")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('scrm:clue:query')")
    @EncryptPhoneNumbers
    public CommonResult<ClueDetailRespVO> getClueDetail(@RequestParam("id") Integer id) {
        ClueDO clue = clueService.getDetail(id);
        // 空值检查
        if (clue == null) {
            return success(null);
        }
        return CommonResult.success(buildClueDetail(clue));
    }

    private ClueDetailRespVO buildClueDetail(ClueDO clue) {
        if (clue == null) {
            return null;
        }
        return buildClueDetailList(singletonList(clue)).get(0);
    }


    public List<ClueDetailRespVO> buildClueDetailList(List<ClueDO> list) {
        if (CollUtil.isEmpty(list)) {
            return java.util.Collections.emptyList();
        }
        // 1.1 获取创建人、负责人列表
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapNotCheckDataPermission(convertListByFlatMap(list, contact -> Stream.of(NumberUtils.parseLong( contact.getUserId()))));
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMapNotCheckDataPermission(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
        // 2. 转换成 VO
        return BeanUtils.toBean(list, ClueDetailRespVO.class, vo -> {
            // 2.1 设置当前负责人、部门
            MapUtils.findAndThen(userMap,  NumberUtils.parseLong(vo.getUserId()), user -> {
                vo.setCluePerson(user.getNickname());
                MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> vo.setClueDepartment(dept.getName()));
            });
        });
    }

    public List<ClueRespVO> buildClueDetailListByPage(List<ClueDO> list) {
        if (CollUtil.isEmpty(list)) {
            return java.util.Collections.emptyList();
        }
        // 1.1 获取创建人、负责人列表
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapNotCheckDataPermission(convertListByFlatMap(list, contact -> Stream.of(NumberUtils.parseLong( contact.getUserId()))));
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMapNotCheckDataPermission(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
        // 2. 转换成 VO
        return BeanUtils.toBean(list, ClueRespVO.class, vo -> {
            // 2.1 设置当前负责人、部门
            MapUtils.findAndThen(userMap,  NumberUtils.parseLong(vo.getUserId()), user -> {
                vo.setCluePerson(user.getNickname());
                MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> vo.setClueDepartment(dept.getName()));
            });
        });
    }


    @GetMapping("/page")
    @Operation(summary = "获得线索分页")
    @PreAuthorize("@ss.hasPermission('scrm:clue:query')")
    public CommonResult<PageResult<ClueRespVO>> getCluePage(@Valid CluePageReqVO pageReqVO, @RequestHeader("Tenant-Id") Integer tenantId) {
        //不是超级管理员默认查询自己的数据-是超级管理员直接查询所有的
        Long loginUserId = getLoginUserId();
        if(CollectionUtils.isAnyEmpty(pageReqVO.getUserId()) && !permissionApi.roleIsSuperAdmin(loginUserId).getCheckedData()) {
            pageReqVO.setUserId(Collections.singletonList(String.valueOf(getLoginUserId())));
        }
        PageResult<ClueDO> pageResult = clueService.getCluePage(pageReqVO, tenantId);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return success(PageResult.empty(pageResult.getTotal()));
        }

        // 拼接数据
        return success(new PageResult<>(buildClueDetailListByPage(pageResult.getList()), pageResult.getTotal()));
    }

    @GetMapping("/export")
    @Operation(summary = "导出线索 Excel")
    @PreAuthorize("@ss.hasPermission('scrm:clue:export')")
    @OperateLog(type = EXPORT)
    public void exportClueExcel(@Valid CluePageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<ClueDO> list = clueService.getCluePageExport(pageReqVO).getList();

        // 导出 Excel
        ExcelUtils.write(response, "线索.xlsx", "数据", ClueExportExcelVo.class, BeanUtils.toBean(list, ClueExportExcelVo.class));
    }

    @PostMapping("/import")
    @Operation(summary = "导入线索 Excel")
    @Parameters({@Parameter(name = "file", description = "Excel 文件", required = true), @Parameter(name = "updateSupport", description = "是否支持更新，默认为 false", example = "true")})
    @PreAuthorize("@ss.hasPermission('scrm:clue:import')")
    public CommonResult<ClueImportExcelRespVO> importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {
        try {
            if (file == null || file.isEmpty()) {
                throw exception(CLUE_IMPORT_NOT_IS_EMPTY); // 文件为空异常
            }
            // 读取Excel文件并转换为 ClueImportExcelVO 列表
            List<ClueImportExcelVO> list = ExcelUtils.readNotNull(file, ClueImportExcelVO.class);
            // 调用业务逻辑进行处理
            return success(clueService.importClueListNotCanUpdate(list));
        } catch (IOException | IllegalArgumentException e) {
            // 捕获文件读取和格式异常
            throw exception(CLUE_IMPORT_FORMAT_ERROR);
        } catch (Exception e) {
            // 捕获其他异常
            throw exception(CLUE_IMPORT_FORMAT_ERROR);
        }

    }

    @GetMapping("/get-import-template")
    @Operation(summary = "获得导入线索 Excel 模板")
    @PreAuthorize("@ss.hasPermission('scrm:clue:import:template')")
    public void importTemplate(HttpServletResponse response, @RequestHeader("Tenant-Id") Integer tenantId) throws IOException {
        // 手动创建导出 demo
        List<ClueImportExcelVO> list = ImportTemplateRandomByTenant.getClueImportTemplateRandomByTenant();
        // 输出
        ExcelUtils.write(response, "线索导入模板.xls", "线索", ClueImportExcelVO.class, list, builderSelectMap(tenantId));
    }


    @PutMapping("/clueInvalidByIds")
    @Operation(summary = "转为无效")
    @PreAuthorize("@ss.hasPermission('scrm:clue:transfer:invalids')")
    public CommonResult<Boolean> clueInvalidByIds(@RequestParam("ids") Set<Long> ids, @RequestParam("state") String state) {
        return success(clueService.clueChangeState(ids, state));
    }

    @PutMapping("/clueTransferAffiliation")
    @Operation(summary = "转移线索")
    @PreAuthorize("@ss.hasPermission('scrm:clue:transfer:owners')")
    public CommonResult<Boolean> clueTransferAffiliation(@Valid @RequestBody ClueTransferAffiliationVo clueTransferAffiliationVo) {
        return success(clueService.clueTransferAffiliation(clueTransferAffiliationVo, getLoginUserId()));
    }


    @PutMapping("/clueTransferClient")
    @Operation(summary = "转为客户")
    @PreAuthorize("@ss.hasPermission('scrm:clue:transfer:clients')")
    public CommonResult<Boolean> clueTransferClient(@Valid @RequestBody ClueTransferClientVo transferClientVo) {
        return success(clueService.clueTransferClient(transferClientVo, getLoginUserId()));
    }


    /**
     * 构建一个包含Excel列及其对应字典值列表的映射
     *
     * @param tenantId - 租户ID，用于获取对应的字典数据
     * @return 包含Excel列及其对应字典值列表的KeyValue对象的列表
     */
    private List<KeyValue<ExcelColumn, List<String>>> builderSelectMap(Integer tenantId) {
        // 创建租户上下文对象，以便获取租户特定的字典数据
        DictTenantContext tenantContext = new DictTenantContext(tenantId);

        // 创建一个列表，用于存储Excel列和对应的字典值列表的映射
        List<KeyValue<ExcelColumn, List<String>>> selectMap = new ArrayList<>();

        // 获取客户来源的字典数据，并将其与Excel列G进行映射
        List<String> clientSourceList = tenantContext.getDictDataLabelList(SCRM_CLUE_CLIENT);
        selectMap.add(new KeyValue<>(ExcelColumn.G, clientSourceList));

        // 获取信息来源的字典数据，并将其与Excel列J进行映射
        List<String> infoSourceList = tenantContext.getDictDataLabelList(SCRM_CLUE_INFO);
        selectMap.add(new KeyValue<>(ExcelColumn.J, infoSourceList));

        // 获取客户质量的字典数据，并将其与Excel列H进行映射
        List<String> clientQualityList = dictDataApi.getDictDataLabelList(SCRM_CLUE_IDEA);
        selectMap.add(new KeyValue<>(ExcelColumn.H, clientQualityList));

        // 获取线索状态的字典数据，并将其与Excel列D进行映射
        List<String> clueStateList = dictDataApi.getDictDataLabelList(SCRM_CLUE_STATE_EXCEPT);
        selectMap.add(new KeyValue<>(ExcelColumn.D, clueStateList));

        // 返回包含所有映射的列表
        return selectMap;
    }


}